//
//  TimeKLineData.cpp
//  Chart
//
//  Created by CaoJun on 13-9-5.
//
//

#include "TimeKLineData.h"
#include <cmath>

using namespace std;
using namespace ytx;

AVGDataHandlerOfKLineData::AVGDataHandlerOfKLineData(TimeKLineData & kLineData) : kLineData(kLineData)
{
    
}

void AVGDataHandlerOfKLineData::handle(ytx::AVGData *avgData, string eventName, void *data)
{
    if (avgData->getId() != kLineData.getId()) {
        return;
    }
    if(eventName == "avgData.update"){
        kLineData.getCloseNewK();
    }
    else if(eventName == "avgData.check"){
        kLineData.checkNeedGetNewK();
    }
    else if(eventName == "quotedPrice.update"){
        kLineData.getCloseNewK();
    }
//    else if(eventName == "avgData.newTradeDay"){
////        kLineData.getKFromTradeDateTo();
//    }
//    else if(eventName == "avgData.stop"){
//        
//    }
//    else if(eventName == "quotedPrice.stop"){
//        
//    }
}


TimeKLineData :: TimeKLineData(string id, string currentDate, LineType::LineType quotationType, string marketType, int toFix, string name, string nickName, bool hasVolume, int limit, int threshold, int buffer, YTXTime tradedate, AVGData * avgData) : KLineData(id, currentDate, quotationType, marketType, toFix, name, nickName, hasVolume, limit, threshold, buffer, tradedate),
avgData(avgData), dataHandler(AVGDataHandlerOfKLineData(*this))
{

}

TimeKLineData :: ~TimeKLineData()
{
    listenOff();
}

void TimeKLineData::listenOn()
{
    listenOff();
    if(avgData){
        avgData->on("quotedPrice.update", &dataHandler);
        avgData->on("avgData.update", &dataHandler);
        avgData->on("avgData.check", &dataHandler);
        avgData->on("avgData.stop", &dataHandler);
        avgData->on("quotedPrice.stop", &dataHandler);
        avgData->on("avgData.newTradeDay", &dataHandler);
    }
}

void TimeKLineData::listenOff()
{
    if (avgData){
        avgData->off("quotedPrice.update", &dataHandler);
        avgData->off("avgData.update", &dataHandler);
        avgData->off("avgData.check", &dataHandler);
        avgData->off("avgData.stop", &dataHandler);
        avgData->off("quotedPrice.stop", &dataHandler);
        avgData->off("avgData.newTradeDay", &dataHandler);
    }
}

bool TimeKLineData::isInLatestNewK(YTXTime tradedate1, YTXTime tradedate2){
    if (LineType::isMinuteLine(quotationType)){
        return (tradedate1 + minutes( LineType::getRequestParamOfQuotationType(quotationType) ) ) >= tradedate2;
    }
    else{
        return (tradedate1 + days(1) ) >= tradedate2;
    }
}

bool TimeKLineData::checkNeedGetNewK(){
    if (!hasDataWithoutClose()) {
        return false;
    }
    KLineItem last =  getLastItemWithoutClose();

    YTXTime limitTime1 = last.dateTime;
    YTXTime limitTime2 = limitTime1 + minutes(LineType::getRequestParamOfQuotationType(quotationType) );
    if (LineType::isMinuteLine(quotationType)) {
        if(avgData->isNewMinK(limitTime1, limitTime2, LineType::getRequestParamOfQuotationType(quotationType) )){
            getKFromTradeDateTo();
            return true;
        }
    }
    else if( quotationType == LineType::L1d ){
//        if(avgData->isLessThanTradeDay(limitTime1)){//后台设计为日K周K不请求当日数据
//            getKFromTradeDateTo();
            return true;
//        }
    }
    else{
        return false;
    }
    return false;
}

void TimeKLineData::getCloseNewK(){
    //向后插入
    
    if(!avgData || !avgData->hasData()){
        return;
    }
    
    KLineItem last = getLastItemWithoutClose();
    
    KLineItem result = {currentDate, numeric_limits<double>::quiet_NaN() };
    
    string date;
    
    if (LineType::isMinuteLine(quotationType)) {
        if(std::isnan(last.open)){
            return;
        }
        YTXTime limitTime1 = last.dateTime;
        YTXTime limitTime2 = limitTime1 + minutes(LineType::getRequestParamOfQuotationType(quotationType));
        
        result = avgData->getOCHL(limitTime1, limitTime2, last.close);
        
//        if ((LineType::isMinutekLine(quotationType))) {
//            
//            
//            
//            result.open = result.high = result.low = result.close = last.close;//
//            
//            double sumValue=0, sumVolume =0;
//            int index = 0;
//            vector<KLineItem>::reverse_iterator it = kLineData.rbegin()+1;
//            //            YTXTime currentTime = result.dateTime.getCurrentTime();
//            //            YTXTime date_monday = currentTime.start_of_week_since_monday();
//            
//            for (; it != kLineData.rend(); ++it, ++index) {
//                //                YTXTime innerTime = (*it).dateTime.getCurrentTime();
//                //                if (innerTime >= date_monday) {
//                sumVolume += (*it).volume;
//                sumValue += (*it).value;
//                //                } else {
//                //                    break;
//                //                }
//            }
//            result.totalVolume -= sumVolume;
//            result.totalValue -= sumValue;//Minute Line
//        }
    }
    else if (quotationType == LineType::L1d){
        if(std::isnan(last.open)){
            last.dateTime = YTXTime::min_date_time();
            last.close = numeric_limits<double>::quiet_NaN();
        }
        YTXTime limitTime1 = last.dateTime;
        
        result = avgData->getOCHLBySnapShort(limitTime1, last.close);// 组合time1 之后的所有数据为一根K线
    }
    
    if(!std::isnan(result.open)){
        date = result.dateTime.toStringYYYYMMddHHmmss();
        
        vector<KLineItem> datas;
        
        vector<string> dates;
        
        datas.push_back(result);
        
        dates.push_back(date);
        
        bool isCalculate = concatCloseNewData(datas, dates);
        
//        if(kLineData.back().dateTime == result.dateTime){
//            closeDataFlag = true;
//        }
        
        if(isCalculate){
            calculateK();
        }
        
    }
}

void TimeKLineData::intervalRequestDataInterface()
{
    if(avgData){
        avgData->requestAvg();
    }
}

// 组装当日K线
void TimeKLineData::calculateTodayKLine()
{
    if(!avgData || !avgData->hasData()){
        return;
    }
    KLineItem last = getLastItemWithoutClose();
    
    KLineItem result = {currentDate, numeric_limits<double>::quiet_NaN() };
    string dateTime;
    long index = LineType::getRequestParamOfQuotationType(quotationType);
    long len = avgData->dateData.size();
    int count = (int)(len / index);
    vector<KLineItem> datas;
    
    vector<string> dates;
    for (int i = 0; i < count;) {
        YTXTime limitTime1 = YTXTime(avgData->dateData[i]);
        YTXTime limitTime2 = limitTime1 + minutes(LineType::getRequestParamOfQuotationType(quotationType));
        result = avgData->getOCHL(limitTime1, limitTime2, avgData->prevValue);
        if(!std::isnan(result.open)){
            dateTime = result.dateTime.toStringYYYYMMddHHmmss();
            
            datas.push_back(result);
            
            dates.push_back(dateTime);
        }
        i += LineType::getRequestParamOfQuotationType(quotationType);
    }
    if (len % index > 0) {
        YTXTime limitTime3 = YTXTime(avgData->dateData[count*index]);
        result = avgData->getOCHL(limitTime3, avgData->prevValue);
        if(!std::isnan(result.open)){
            dateTime = result.dateTime.toStringYYYYMMddHHmmss();
            
            datas.push_back(result);
            
            dates.push_back(dateTime);
        }
    }
    if (!dates.size()) {
        avgData->requestAvg();
        return;
    }
    bool isCalculate = concatCloseNewData(datas, dates);
    
    if(isCalculate){
        calculateK();
    }    
}
